import uiconst
import uicls
import uiutil
import uthread
import blue
import base
import trinity
import util
import log
ALIGNMENTTRIGGERS = ('left', 'top', 'width', 'height', 'align', 'padLeft', 'padTop', 'padRight', 'padBottom', 'display', 'parent')
ATTRIBUTE_REMAP = {'clipChildren': 'clip'}

class BaseDecoCore(object):
    __guid__ = 'uitest.BaseDecoCore'
    __push_alignments__ = (uiconst.TOLEFT,
     uiconst.TOTOP,
     uiconst.TORIGHT,
     uiconst.TOBOTTOM)
    __affected_by_push_alignments__ = (uiconst.TOLEFT,
     uiconst.TOTOP,
     uiconst.TORIGHT,
     uiconst.TOBOTTOM,
     uiconst.TOALL)
    default_name = 'newbasedecocore'
    default_padding = None
    default_padLeft = 0
    default_padTop = 0
    default_padRight = 0
    default_padBottom = 0
    default_parent = None
    default_idx = -1
    default_state = uiconst.UI_NORMAL
    default_align = uiconst.TOPLEFT
    default_pos = None
    default_left = 0
    default_top = 0
    default_width = 0
    default_height = 0
    default_hint = ''
    default_blurFactor = 0.0

    def __getattr__(self, k):
        if ((k in 'sr,wr') and (k not in self.__dict__)):
            self.sr = uiutil.Bunch()
            self.wr = util.WeakRefAttrObject()
        if (k == 'rectLeft'):
            return self.texturePrimary.srcX
        if (k == 'rectTop'):
            return self.texturePrimary.srcY
        if (k == 'rectWidth'):
            return self.texturePrimary.srcWidth
        if (k == 'rectHeight'):
            return self.texturePrimary.srcHeight
        if (k in ATTRIBUTE_REMAP):
            return getattr(self, ATTRIBUTE_REMAP[k])
        if (k == 'parent'):
            return self.__dict__.get(k, None)
        if (k == 'destroyed'):
            return self.__dict__.get(k, False)
        if (k in self.__dict__):
            return self.__dict__[k]
        raise AttributeError, k



    def SearchForMyParent(self, checkParent):
        for child in checkParent.children:
            if (child == self):
                return checkParent
            if hasattr(child, 'children'):
                ret = self.SearchForMyParent(child)
                if (ret is not None):
                    return ret




    def OnSetAttr(self, k, v):
        if (k == 'state'):
            self.SetState(v)
        elif ((k in ALIGNMENTTRIGGERS) and getattr(self, '_inited', False)):
            if (self.GetAlign() in self.__push_alignments__):
                self.FlagDirtyToDesktop()
            else:
                if ((k != 'display') or ((k == 'display') and v)):
                    self.FlagDirtyToDesktop()
        elif ((k == 'hint') and getattr(uicore, 'desktop', None)):
            if (hasattr(uicore.desktop, 'GetMouseOver') and (uicore.desktop.GetMouseOver() is self)):
                uicore.desktop.UpdateHint()
        elif (k in ATTRIBUTE_REMAP):
            setattr(self, ATTRIBUTE_REMAP[k], v)



    def _Initialize(self, *args, **kw):
        self._inited = False
        self._curveSets = []
        self._lastAlignmentUpdate = None
        self._pickChildrenOnly = None
        self._alignmentDirty = False
        self.destroyed = False
        self.dead = False
        self.align = uiconst.RELATIVE
        self.left = 0
        self.top = 0
        self.width = 0
        self.height = 0
        self.padLeft = 0
        self.padTop = 0
        self.padRight = 0
        self.padBottom = 0
        self._inited = True
        self.ApplyAttributes(uiutil.Bunch(kw))



    def ApplyAttributes(self, attributes):
        self.name = attributes.get('name', self.default_name)
        parent = attributes.get('parent', self.default_parent)
        if parent:
            self.SetParent(attributes.get('parent', self.default_parent), attributes.get('idx', self.default_idx))
        pos = attributes.get('pos', self.default_pos)
        if (pos is not None):
            (left, top, width, height,) = pos
        else:
            (left, top, width, height,) = (0, 0, 0, 0)
        if ('left' in attributes):
            left = attributes.left
        if ('top' in attributes):
            top = attributes.top
        if ('width' in attributes):
            width = attributes.width
        if ('height' in attributes):
            height = attributes.height
        self.SetSize(width, height)
        self.SetPosition(left, top)
        padding = attributes.get('padding', self.default_padding)
        if (padding is not None):
            (padLeft, padTop, padRight, padBottom,) = padding
        else:
            (padLeft, padTop, padRight, padBottom,) = (0, 0, 0, 0)
        padLeft = (attributes.get('padLeft', self.default_padLeft) or padLeft)
        padTop = (attributes.get('padTop', self.default_padTop) or padTop)
        padRight = (attributes.get('padRight', self.default_padRight) or padRight)
        padBottom = (attributes.get('padBottom', self.default_padBottom) or padBottom)
        self.SetPadding(padLeft, padTop, padRight, padBottom)
        self.state = attributes.get('state', self.default_state)
        self.SetState(attributes.get('state', self.default_state))
        self.SetAlign(attributes.get('align', self.default_align))
        self.SetHint(attributes.get('hint', self.default_hint))
        self.SetBlurFactor(attributes.get('blurFactor', self.default_blurFactor))
        self._alignmentDirty = True
        self.UpdateAlignment()



    def _Destroy(self, i):
        if getattr(self, 'destroyed', True):
            return 
        if hasattr(self, 'children'):
            lenChildren = len(self.children)
            for i in xrange(lenChildren):
                each = self.children[((lenChildren - i) - 1)]
                if hasattr(each, '_Destroy'):
                    each._Destroy((i + 1))
                else:
                    self.children.remove(each)

        curveSets = getattr(self, '_curveSets', None)
        if curveSets:
            for each in curveSets:
                if (each in uicore.scene.curveSets):
                    uicore.scene.curveSets.remove(each)

        parent = self.GetParent()
        if (parent and (self in parent.children[:])):
            parent.children.remove(self)
        if ('parent' in self.__dict__):
            del self.__dict__['parent']
        self._OnClose()
        self.dead = True



    def LoadBlueFile(self, filename):
        return 



    def ProcessEvent(self, eventID):
        if (eventID == uiconst.UI_MOUSEEXIT):
            (handlerArgs, handler,) = self.FindHandler('OnMouseExit')
        elif (eventID == uiconst.UI_MOUSEENTER):
            (handlerArgs, handler,) = self.FindHandler('OnMouseEnter')
        else:
            raise NotImplementedError
        if handler:
            self.ExecuteHandler(eventID, handler, handlerArgs)



    def FindHandler(self, handlerName):
        method = getattr(self, handlerName, None)
        if method:
            return ((self), method)
        else:
            method = getattr(self, ('_' + handlerName), None)
            if method:
                return ((), method)
            return (None, None)



    def ExecuteHandler(self, eventID, Handler, args):
        customArgs = ()
        if (type(Handler) == type(())):
            customArgs = Handler[1:]
            Handler = Handler[0]
        if Handler:
            args = (customArgs + args)
            if (eventID in (uiconst.UI_CLICK,
             uiconst.UI_KEYUP,
             uiconst.UI_KEYDOWN)):
                uthread.new(Handler, *args)
            else:
                try:
                    Handler(*args)
                except Exception:
                    log.LogException()



    def CreateCurveSet(self):
        curveSet = trinity.TriCurveSet()
        self.AddCurveSet(curveSet)
        return curveSet



    def AddCurveSet(self, curveSet):
        self._curveSets.append(curveSet)
        uicore.scene.curveSets.append(curveSet)



    def RemoveCurveSet(self, curveSet):
        if (curveSet in self._curveSets):
            self._curveSets.remove(curveSet)
        if (curveSet in uicore.scene.curveSets):
            uicore.scene.curveSets.remove(curveSet)



    def Close(self):
        self.SetDisplayState(False)
        self._Destroy(0)



    def SetBlurFactor(self, factor):
        self.blurFactor = factor



    def GetParent(self):
        return getattr(self, 'parent', None)



    def SetPosition(self, left = None, top = None):
        if ((left is not None) and (self.left != left)):
            self.left = left
        if ((top is not None) and (self.top != top)):
            self.top = top



    def SetLeft(self, left):
        if (left != self.left):
            self.left = left



    def SetTop(self, top):
        if (top != self.top):
            self.top = top



    def SetSize(self, width = None, height = None):
        if (width is not None):
            self.width = width
        if (height is not None):
            self.height = height



    def SetWidth(self, width):
        if (width != self.width):
            self.width = width



    def SetHeight(self, height):
        if (height != self.height):
            self.height = height



    def FlagDirtyToDesktop(self):
        self._alignmentDirty = True
        item = self
        while item.parent:
            item.parent._alignmentDirty = True
            item = item.parent




    def UpdateAlignment(self, budget = None, *args, **kw):
        if (self.destroyed or (not self.display)):
            return budget
        else:
            parent = self.GetParent()
            if (parent is None):
                return budget
            if (self.display is False):
                return budget
            (setLeft, setTop, setWidth, setHeight,) = (self.left,
             self.top,
             self.width,
             self.height)
            align = self.GetAlign()
            if not self._alignmentDirty:
                if (budget and (align in self.__push_alignments__)):
                    (budgetLeft, budgetTop, budgetWidth, budgetHeight,) = budget
                    (padLeft, padTop, padRight, padBottom,) = self.GetPadding()
                    if (align == uiconst.TOLEFT):
                        budgetLeft = (((budgetLeft + padLeft) + setWidth) + padRight)
                        budgetWidth = (((budgetWidth - padLeft) - setWidth) - padRight)
                    elif (align == uiconst.TORIGHT):
                        budgetWidth = (((budgetWidth - padLeft) - setWidth) - padRight)
                    elif (align == uiconst.TOTOP):
                        budgetTop = (((budgetTop + padTop) + setHeight) + padBottom)
                        budgetHeight = (((budgetHeight - padTop) - setHeight) - padBottom)
                    elif (align == uiconst.TOBOTTOM):
                        budgetHeight = (((budgetHeight - padTop) - setHeight) - padBottom)
                    budget = (budgetLeft,
                     budgetTop,
                     budgetWidth,
                     budgetHeight)
                return budget
            preDWidth = self.displayWidth
            preDHeight = self.displayHeight
            if (align in self.__affected_by_push_alignments__):
                if (budget is None):
                    budget = self.parent.GetAlignmentBudgetForChild(self)
                (budgetLeft, budgetTop, budgetWidth, budgetHeight,) = budget
                (padLeft, padTop, padRight, padBottom,) = self.GetPadding()
                if (align == uiconst.TOLEFT):
                    self.displayX = (budgetLeft + padLeft)
                    self.displayY = (budgetTop + padTop)
                    self.displayHeight = ((budgetHeight - padTop) - padBottom)
                    self.displayWidth = setWidth
                    budgetLeft = (((budgetLeft + padLeft) + setWidth) + padRight)
                    budgetWidth = (((budgetWidth - padLeft) - setWidth) - padRight)
                elif (align == uiconst.TORIGHT):
                    self.displayX = (((budgetLeft + budgetWidth) - setWidth) - padRight)
                    self.displayY = (budgetTop + padTop)
                    self.displayHeight = ((budgetHeight - padTop) - padBottom)
                    self.displayWidth = setWidth
                    budgetWidth = (((budgetWidth - padLeft) - setWidth) - padRight)
                elif (align == uiconst.TOTOP):
                    self.displayX = (budgetLeft + padLeft)
                    self.displayY = (budgetTop + padTop)
                    self.displayWidth = ((budgetWidth - padLeft) - padRight)
                    self.displayHeight = setHeight
                    budgetTop = (((budgetTop + padTop) + setHeight) + padBottom)
                    budgetHeight = (((budgetHeight - padTop) - setHeight) - padBottom)
                elif (align == uiconst.TOBOTTOM):
                    self.displayX = (budgetLeft + padLeft)
                    self.displayY = (((budgetTop + budgetHeight) - setHeight) - padBottom)
                    self.displayWidth = ((budgetWidth - padLeft) - padRight)
                    self.displayHeight = setHeight
                    budgetHeight = (((budgetHeight - padTop) - setHeight) - padBottom)
                elif (align == uiconst.TOALL):
                    self.displayX = (budgetLeft + padLeft)
                    self.displayY = (budgetTop + padTop)
                    self.displayWidth = ((budgetWidth - padLeft) - padRight)
                    self.displayHeight = ((budgetHeight - padTop) - padBottom)
                else:
                    raise NotImplementedError
                budget = (budgetLeft,
                 budgetTop,
                 budgetWidth,
                 budgetHeight)
            else:
                (budgetWidth, budgetHeight,) = (self.parent.displayWidth, self.parent.displayHeight)
                self.displayWidth = setWidth
                self.displayHeight = setHeight
                if (align == uiconst.RELATIVE):
                    self.displayX = setLeft
                    self.displayY = setTop
                elif (align == uiconst.TOPRIGHT):
                    self.displayX = ((budgetWidth - setWidth) - setLeft)
                    self.displayY = setTop
                elif (align == uiconst.BOTTOMRIGHT):
                    self.displayX = ((budgetWidth - setWidth) - setLeft)
                    self.displayY = ((budgetHeight - setHeight) - setTop)
                elif (align == uiconst.BOTTOMLEFT):
                    self.displayX = setLeft
                    self.displayY = ((budgetHeight - setHeight) - setTop)
                elif (align == uiconst.CENTER):
                    self.displayX = int((((budgetWidth - setWidth) / 2) + setLeft))
                    self.displayY = int((((budgetHeight - setHeight) / 2) + setTop))
                elif (align == uiconst.CENTERBOTTOM):
                    self.displayX = int((((budgetWidth - setWidth) / 2) + setLeft))
                    self.displayY = ((budgetHeight - setHeight) - setTop)
                elif (align == uiconst.CENTERTOP):
                    self.displayX = int((((budgetWidth - setWidth) / 2) + setLeft))
                    self.displayY = setTop
                elif (align == uiconst.CENTERLEFT):
                    self.displayX = setLeft
                    self.displayY = int((((budgetHeight - setHeight) / 2) + setTop))
                elif (align == uiconst.CENTERRIGHT):
                    self.displayX = ((budgetWidth - setWidth) - setLeft)
                    self.displayY = int((((budgetHeight - setHeight) / 2) + setTop))
                else:
                    raise NotImplementedError
            self._alignmentDirty = False
            if ((preDWidth != self.displayWidth) or (preDHeight != self.displayHeight)):
                uthread.new(self._OnResize)
            return budget



    def SetParent(self, parent, idx = None):
        currentParent = self.GetParent()
        if ((currentParent == parent) and (self in parent.children)):
            currentIndex = parent.children.index(self)
            if (idx in (None, -1)):
                idx = len(parent.children)
            if (currentIndex == idx):
                return 
        if (currentParent and hasattr(currentParent, 'RemoveChild')):
            currentParent.RemoveChild(self)
        if (parent is not None):
            parent.AddChild(self, idx)
            self.parent = parent
            if (self.GetAlign() in self.__push_alignments__):
                self.parent.UpdateAlignment(kickChilds=True)
        else:
            del self.__dict__['parent']



    def SetPadding(self, padLeft = None, padTop = None, padRight = None, padBottom = None):
        if ((padLeft is not None) and (padLeft != self.padLeft)):
            self.padLeft = padLeft
        if ((padTop is not None) and (padTop != self.padTop)):
            self.padTop = padTop
        if ((padRight is not None) and (padRight != self.padRight)):
            self.padRight = padRight
        if ((padBottom is not None) and (padBottom != self.padBottom)):
            self.padBottom = padBottom



    def GetPadding(self):
        return (self.padLeft,
         self.padTop,
         self.padRight,
         self.padBottom)



    def SetState(self, state):
        if (state == uiconst.UI_NORMAL):
            self.SetDisplayState(True)
            self.SetPickState(uiconst.TR2_SPS_ON)
        elif (state == uiconst.UI_PICKCHILDREN):
            self.SetDisplayState(True)
            self.SetPickState(uiconst.TR2_SPS_CHILDREN)
        elif (state == uiconst.UI_DISABLED):
            self.SetDisplayState(True)
            self.SetPickState(uiconst.TR2_SPS_OFF)
        elif (state == uiconst.UI_HIDDEN):
            self.SetDisplayState(False)
            self.SetPickState(uiconst.TR2_SPS_OFF)



    def SetPickState(self, pickState):
        self._pickChildrenOnly = bool((pickState == uiconst.TR2_SPS_CHILDREN))
        if (pickState != self.pickState):
            self.pickState = pickState



    def SetDisplayState(self, displayState):
        if (displayState != self.display):
            self.display = bool(displayState)



    def GetState(self):
        return 



    def SetAlign(self, align):
        self._previousAlign = getattr(self, 'align', None)
        if (align != self.align):
            self.align = align



    def GetAlign(self):
        return self.align



    def GetAbsolute(self):
        (l, t,) = self.GetAbsolutePosition()
        return (l,
         t,
         self.displayWidth,
         self.displayHeight)



    def GetAbsoluteSize(self):
        return (self.displayWidth, self.displayHeight)



    def GetAbsolutePosition(self):
        item = self
        l = 0
        t = 0
        while getattr(item, 'parent', None):
            l += item.displayX
            t += item.displayY
            item = getattr(item, 'parent', None)

        return (l, t)



    def SetOrder(self, newIndex):
        if (self.parent and (self in self.parent.children)):
            self.parent.children.remove(self)
            self.parent.children.insert(newIndex, self)
            self.parent.UpdateAlignment()
        else:
            log.LogError("Someone is trying to set children onder of item which doesn't have parent", self.name)



    def SetFocus(self):
        if hasattr(self, '_OnSetFocus'):
            self._OnSetFocus()
        elif hasattr(self, 'OnSetFocus'):
            self.OnSetFocus(self)



    def SetHint(self, hint):
        if (hint != self.GetHint()):
            self.hint = hint



    def GetHint(self):
        return getattr(self, 'hint', None)



    def Hide(self, *args):
        if self.display:
            self.display = False



    def Show(self, *args):
        if not self.display:
            self.display = True



    def IsHidden(self):
        return (not self.display)



    def Disable(self, *args):
        self.opacity = 0.5
        self.SetPickState(uiconst.TR2_SPS_OFF)



    def Enable(self, *args):
        if self._pickChildrenOnly:
            self.SetPickState(uiconst.TR2_SPS_OFF)
        else:
            self.SetPickState(uiconst.TR2_SPS_CHILDREN)
        self.opacity = 1.0



    def _OnMouseDown(self, *args):
        return 



    def _OnMouseUp(self, *args):
        return 



    def _OnResize(self, *args):
        return 



    def _OnClose(self, *args):
        return 




